#include "legami.h"

Legami::Legami(QSqlDatabase* db): db(db) {
}

Legami::~Legami(){
    delete db;
    //QVector<Account*> utenti
    for(int i=0;i!=utenti.size();i++){
        delete utenti[i];
    }
    //QVector<Gruppo*> gruppi
    for(int i=0;i!=gruppi.size();i++){
        delete gruppi[i];
    }
}

QString Legami::username= "admin";  //campo statico username
QString Legami::pwd= "password";    //campo statico pwd

QString Legami::getU(){
    return username;
}

QString Legami::getP(){
    return pwd;
}

Account* Legami::upgradeB(Account* utente,Username* username, Profilo* profilo,Contatto* c){
    for(QVector<Account*>::iterator it= utenti.begin(); it!= utenti.end(); it++){
        if((*it)==utente){
            (*it)= new BusinessAccount(username, profilo);
            updateAll(*it,utente,c);    //normalizzo il tutto
            delete utente;  //dealloco la memoria del vecchio account,quello usato prima dell'upgrade!
            return (*it);
        }
    }
    return 0;
}

Account* Legami::upgradeE(Account* utente,Username* username, Profilo* profilo,Contatto* c){
    for(QVector<Account*>::iterator it= utenti.begin(); it!= utenti.end(); it++){
        if((*it)==utente){
            (*it)= new ExecutiveAccount(username,profilo);
            updateAll(*it,utente,c);    //normalizzo il tutto
            delete utente;  //vedi sopra
            return (*it);
        }
    }
    return 0;
}

void Legami::updateAll(Account* it, Account* utente, Contatto* c){
            //Creo e assegno la copia dei collegamenti e dei gruppi dell'account che sto upgradando
            QVector<Contatto*> coll= utente->getColl();
            QVector<Gruppo*> gru= utente->getGru();
            it->setColl(coll);
            it->setGru(gru);
            //per ogni utente del database, cambio il puntatore all'account che sto upgradando, in modo che punti a quello nuovo
            //e non piu' a quello che poi eliminero'.
            for(QVector<Account*>::iterator it_in= utenti.begin(); it_in!=utenti.end(); it_in++){
                (*it_in)->updateCon(c);
            }
            //idem di sopra,ma con i gruppi,piu' semplice.
            for(QVector<Gruppo*>::iterator itgr= gruppi.begin(); itgr!= gruppi.end(); itgr++){
                (*itgr)->updateGru(it);
            }
            utente->clearvector();
            //indispensabile,senno' la delete al ritorno dalla funzione mi elimina la memoria dei vettori con relativi contatti
            //presenti e quindi i nuovi puntatori non punterebbero a niente!
}

QVector<Account*> Legami::getUtenti() const{
    return utenti;
}

QVector<Gruppo*> Legami::getGruppi() const{
    return gruppi;
}

Account* Legami::getAcc(User* us){//account corrispettivo al proprio user! User->Account
    for(QVector<Account*>::iterator it= utenti.begin(); it!= utenti.end(); it++)
        if((*it)->getNick()==us->getNick())
            return (*it);
    return 0;
}

void Legami::add(Account* a){
    utenti.push_back(a);
}

void Legami::addgruppo(Gruppo* g){
    gruppi.push_back(g);
}

void Legami::elimina(Account* acc){ //Disattivazione di un account
    for(QVector<Account*>::iterator it= utenti.begin(); it!= utenti.end(); it++){
        if(acc!=(*it)){ //un account non puo' essere in collegamento con se stesso!
            (*it)->eraseContatto(acc);
        }
    }

    for(QVector<Gruppo*>::iterator it= gruppi.begin(); it!=gruppi.end(); it++){
        (*it)->deleteUser(acc);  //prima elimino l'account dai suoi gruppi
        acc->eraseGruppo((*it)); //elimino dall'account che sto eliminando il gruppo in questione.
    }

    //Per evitare interferenze in gruppi (spiegate sotto*) mentre si scorre gruppi stesso (che causerebbero inconsistenze) creare un
    //vettore di copia di supporto, che copiando i puntatori agisce sulle zone di memoria (condivise) da essi puntati,
    //da usare come vettore di scorrimento. Il vettore poi si elimina!!
    QVector<Gruppo*>* support= new QVector<Gruppo*>();  //creazione
    for(QVector<Gruppo*>::iterator it= gruppi.begin(); it!=gruppi.end(); it++)  //si riempie con le copie
        support->push_back(*it);

    for(QVector<Gruppo*>::iterator it= support->begin(); it!=support->end(); it++){
        if((*it)->getProp()==acc->getNick())
            deletegruppo((*it));
    }
    delete support; //via il vettore di supporto!!
    // *: all'inizio non era contemplato il vettore di supporto,ma scorrendo l'iteratore,quando esso trovava il puntatore al gruppo
    //da eliminare,una volta eseguito la cancellazione in questione non riusciva a raggiungere il puntatore successivo,crashando prima.

    for(QVector<Account*>::iterator it= utenti.begin(); it!=utenti.end(); it++) //lo elimino da legami
        if((*it)==acc){
            utenti.erase(it);   //la delete sull'account in questione viene fatta al ritorno in deleteacc()
            return;
        }
}

bool Legami::deletegruppo(Gruppo* g){
    for(QVector<Account*>::iterator it= utenti.begin(); it!= utenti.end(); it++)
        (*it)->eraseGruppo(g);

    for(QVector<Gruppo*>::iterator it= gruppi.begin(); it!= gruppi.end(); it++){
        if((*it)==g){
            gruppi.erase(it);
            return true;
        }
    }
    return false;
}

bool Legami::checkgroup(QString id){    //controllo che non ci sia gia' un gruppo con id dato
    for(QVector<Gruppo*>::iterator it= gruppi.begin(); it!= gruppi.end(); it++)
        if((*it)->getId()==id)
            return false;
    return true;
}

void Legami::fillUsers(){
    for(QVector<Account*>::iterator it= utenti.begin(); it!= utenti.end(); it++){
        QString utente= (*it)->getNick();
        QSqlQuery query_user(*db);
        query_user.prepare("Select tag, user2 from contatti where user1= :user");
        query_user.bindValue(":user", utente);
        query_user.exec();
        while(query_user.next()){ //per l'user da aggiungere (user2) mi preparo il suo username
            QString u= query_user.value(1).toString();  //Username user2
            QSqlQuery subquery_user(*db);
            subquery_user.prepare("Select password, nome, cognome,sesso from utenti where username= :username");
            subquery_user.bindValue(":username", u);
            subquery_user.exec();
            QString p;
            QString n;
            QString c;
            int g;
            while (subquery_user.next()){
                p= subquery_user.value(0).toString();   //user2
                n= subquery_user.value(1).toString();
                c= subquery_user.value(2).toString();
                g= subquery_user.value(3).toInt();
            }
            Username* username= new Username(n,c,u,p,g);          //Username + password = Username*
            QString birthday, new_school, old_school, link1, link2;
            QSqlQuery subquery_1(*db);
            subquery_1.prepare("Select distinct birthday,new_school, old_school, link1, link2 from info where username= :usern");
            subquery_1.bindValue(":usern", u);
            subquery_1.exec();
            while(subquery_1.next()){
                birthday= subquery_1.value(0).toString();
                new_school= subquery_1.value(1).toString();
                old_school= subquery_1.value(2).toString();
                link1= subquery_1.value(3).toString();
                link2= subquery_1.value(4).toString();
            }   // qui ho birthday, new_school, old_school
            QSqlQuery subquery_2(*db);
            subquery_2.prepare("Select interest from info where username= :username");
            subquery_2.bindValue(":username", u);
            subquery_2.exec();
            QVector<QString> interests;
            while(subquery_2.next()){
                QString interest= subquery_2.value(0).toString();
                interests.push_back(interest);
            }   // uscito da qui ho il vettore di interessi

            Info* info= new Info(birthday, interests, new_school, old_school, link1, link2); //info user2
            Profilo* pr= new Profilo(info);                        //profilo user2 da info
            int tag= query_user.value(0).toInt();
            Tag* t= new Tag(tag);                                   //tag user2
            Contatto* contact= new Contatto(t, username, pr);//contatto user2
            (*it)->insertContatto(contact);
        }
    }
}

void Legami::fillGroups(){
    //per ogni gruppo, tutti i membri di quel gruppo sul vettore e aggiungere gruppo al vector dedicato in user
    QString username;
    for(QVector<Account*>::iterator it= utenti.begin(); it!= utenti.end(); it++){
        username= (*it)->getNick();
        QSqlQuery subquery_gruppo(*db);
        subquery_gruppo.prepare("Select id_group from gruppi where username= :user");
        subquery_gruppo.bindValue(":user", username);
        subquery_gruppo.exec();
        while(subquery_gruppo.next()){
            QString id= subquery_gruppo.value(0).toString();
            int i2=0;
            for(QVector<Gruppo*>::iterator it_g= gruppi.begin(); it_g!= gruppi.end(); it_g++, i2++){
                if((*it_g)->getId()==id){
                    (*it)->insertGruppo(*it_g);
                    (*it_g)->insertUser(*it);
                }
            }
        }
    }
}

bool Legami::foundusername(QString user){  //controllo che username/nick sia disponibile all'uso al momento della registrazione
    for(QVector<Account*>::iterator it= utenti.begin(); it!= utenti.end(); it++){
        if((*it)->getNick()==user)
            return true;
    }
    return false;
}

bool Legami::foundgruppo(Gruppo* g) throw(logic_error){
    for(QVector<Gruppo*>::iterator it= gruppi.begin(); it!= gruppi.end(); it++)
        if((*it)==g)
            return true;
    //arrivo alla fine, gruppo non trovato -> Errore logico!
    throw logic_error();
}

bool Legami::foundacc(User* user) throw(logic_error){
    for(QVector<Account*>::iterator it= utenti.begin(); it!= utenti.end(); it++)
        if((*it)==user)
            return true;
    //arrivo alla fine, account non trovato -> Errore logico
    throw logic_error();
}

Account* Legami::verify(QString us, QString pw){    //questo ci serve per tabUser,dove abbiamo bisogno di un current da subito!
    for(QVector<Account*>::iterator it= utenti.begin(); it!= utenti.end(); it++){
        if(((*it)->getNick()==us)&&((*it)->getPwd()==pw))
            return (*it);
    }
    return 0;
}

bool Legami::aut(QString us, QString pw){
    if((us==this->getU())&&(pw==this->getP()))
        return true;
    else return false;
}

QVector<Account*>* Legami::searchU(int limit, QString nome, QString cognome, QString username){
    QVector<Account*>* risultato= new QVector<Account*>();
    if(!limit)
        limit= utenti.count();
    int i=0;
    for(QVector<Account*>::iterator it= utenti.begin();i<limit && it!=utenti.end(); it++){
        if(!(nome.isEmpty())){
            if(!(cognome.isEmpty())){
                if(!(username.isEmpty())){ //nome+cognome+username
                    if((*it)->getNome()==nome && (*it)->getCognome()==cognome && (*it)->getNick()==username){
                        risultato->push_back(*it);
                        i++;
                    }
                }
                else{   //nome+cognome
                    if((*it)->getNome()==nome && (*it)->getCognome()==cognome){
                        risultato->push_back(*it);
                        i++;
                    }
                }
            }
            else{
                if(!username.isEmpty()){    //nome+username
                    if((*it)->getNome()==nome && (*it)->getNick()==username){
                        risultato->push_back(*it);
                        i++;
                    }
                }
                else{   //solo nome
                    if((*it)->getNome()==nome){
                        risultato->push_back(*it);
                        i++;
                    }
                }
            }
        }
        else{   //no nome
            if(!(cognome.isEmpty())){
                if(!(username.isEmpty())){  //cognome+username
                    if((*it)->getCognome()==cognome && (*it)->getNick()==username){
                        risultato->push_back(*it);
                        i++;
                    }
                }
                else{   //cognome
                    if((*it)->getCognome()==cognome){
                        risultato->push_back(*it);
                        i++;
                    }
                }
            }
            else{   //no cognome
                if((*it)->getNick()==username){     //solo username
                    risultato->push_back(*it);
                    i++;
                }
            }
        }
    }
    return risultato;
}

QVector<Gruppo*>* Legami::searchG(int limit, QString id, QString nome, QString prop){
    QVector<Gruppo*>* risultato= new QVector<Gruppo*>();
    if(!limit)
        limit= gruppi.count();
    int i=0;
    for(QVector<Gruppo*>::iterator it= gruppi.begin();i<limit && it!=gruppi.end(); it++){
        if(!(id.isEmpty())){
            if(!(nome.isEmpty())){
                if(!(prop.isEmpty())){ //id+nome+proprietario
                    if((*it)->getId()==id && (*it)->getNome()==nome && (*it)->getProp()==prop){
                        risultato->push_back(*it);
                        i++;
                    }
                }
                else{   //id+nome
                    if((*it)->getId()==id && (*it)->getNome()==nome){
                        risultato->push_back(*it);
                        i++;
                    }
                }
            }
            else{
                if(!prop.isEmpty()){    //id+proprietario
                    if((*it)->getId()==id && (*it)->getProp()==prop){
                        risultato->push_back(*it);
                        i++;
                    }
                }
                else{   //solo id
                    if((*it)->getId()==id){
                        risultato->push_back(*it);
                        i++;
                    }
                }
            }
        }
        else{   //no id
            if(!(nome.isEmpty())){
                if(!(prop.isEmpty())){  //nome+prop
                    if((*it)->getNome()==nome && (*it)->getProp()==prop){
                        risultato->push_back(*it);
                        i++;
                    }
                }
                else{   //nome
                    if((*it)->getNome()==nome){
                        risultato->push_back(*it);
                        i++;
                    }
                }
            }
            else{   //no nome
                if((*it)->getProp()==prop){     //solo username
                    risultato->push_back(*it);
                    i++;
                }
            }
        }
    }
    return risultato;
}

void Legami::clear(){   //chiamato da TabAmm al momento della conferma della volonta' di azzerare il database!
    gruppi.clear();
    utenti.clear();
}
